home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 001 / midiplay / c / MP_INTP < prev    next >
Encoding:
Text File  |  1993-01-08  |  21.9 KB  |  636 lines

  1. /*
  2.  * File: mp_intp.c
  3.  * SGoldthorpe  20-Jul-91
  4.  */
  5.  
  6. /*
  7.  * mp_intp - the midi file interpreter for midiplay
  8.  * This software is (C) 1991 Stephen Goldthorpe but it's FREE!  Usual
  9.  * disclaimers and notices about this software not being sold for profit.
  10.  * But you may take all you want from the code though!  If you have any
  11.  * suggestions/bug fixes please get in contact with me.  I don't want to
  12.  * maintain code i've never even seen before (life's hard enough without all
  13.  * of that)!
  14.  *                                              -Steve Goldthorpe
  15.  * Phone (DAYTIME UK):  +44 707 382350
  16.  * Internet E-Mail:     SGoldthorpe.wgc-e@rx.xerox.com
  17.  *                      goldthor@arisia.xerox.com
  18.  *
  19.  * Version 0.5 by Piet van Oostrum <piet@cs.ruu.nl>
  20.  * November 1991.
  21.  * I made the following changes:
  22.  * 1. Files > 32767 wouldn't play. I have changed a couple of ints to
  23.  *    LONG. Also malloc'ed the buffer with a variable rather than a fixed size.
  24.  * 2. replaced array referenced with a[i] rather than *(a+i). I find this
  25.  *    more readable but it has the same meaning.
  26.  * 3. Midifiles of more than about 3 minutes didn't play right. I think
  27.  *    this is a bug in ltod (long to double) in the floating point lib. I
  28.  *    changed the timing from using floating point arithmetic to LONG
  29.  *    arithmetic.
  30.  *    Anyway the timing was not robust in the presence of tempo changes
  31.  *    because the new time per beat would be applied to the time from the
  32.  *    beginning of the piece rather than from the time of the tempo change.
  33.  * 4. I introduced the -T option to send timing commands. This can be
  34.  *    used to trigger a drum computer or an arranger.
  35.  *
  36.  * NOTE: I distribute this version with the consent of Steve
  37.  * Goldthorpe. I think he should not be bothered with bugs in my version!
  38.  */
  39.  
  40. #include        <stdio.h>
  41. #include        <time.h>
  42. #include        <string.h>
  43. #include        "kernel.h"
  44. #include        "bbc.h"
  45.  
  46. /* and for the atari OS stuff */
  47. /* #include        <osbind.h> */
  48.  
  49.  
  50.  
  51. #include        "mp_gbls.h"
  52.  
  53. /* GLOBAL VARIABLES */
  54. /* The track_delta's are in units of 1/division clockticks */
  55. /* time_per_beat is the length of a quarter note in clock ticks */
  56.    
  57. static long     track_delta[MAX_TRACKS], division, time_per_beat;
  58. static BYTE     *track_pos[MAX_TRACKS];
  59. static long     track_left[MAX_TRACKS];
  60. static int      track_finished[MAX_TRACKS];
  61. static clock_t  clock_orig;
  62. static char     *gFile;
  63. static WORD     format, tracks;
  64. static int      finished_tracks;
  65. static int      trnr;
  66. static long     clock_delta, clock_time;
  67.  
  68. /* FUNCTION DECLS */
  69.  
  70. BOOL            interp(BYTE *buffer, char *file, LONG len);
  71. int             sysex_event(BYTE event);
  72. int             meta_event(void);
  73. static int      system_common(BYTE event);
  74. static int      system_real_time(void);
  75. static void     all_notes_off(void);
  76. static void     truncated(void);
  77.  
  78.  
  79. /* MACRO FUNCTIONS */
  80. /* the error checking may be a bit OTT but I'm gonna do it anyway  (helps
  81.    catch those naughty bugs - and bad files) */
  82. #define GET32BITS(dw,p,l)       dw=(((LONG)(*p)<<24)+                   \
  83.                                         ((LONG)(*(p+1))<<16)+           \
  84.                                         (((LONG)*(p+2))<<8)+            \
  85.                                         (LONG)(*(p+3)));                \
  86.                                 if(l<4)                                 \
  87.                                 {       truncated();                    \
  88.                                         return(FALSE);                  \
  89.                                 }                                      \
  90.                                 p += 4; l -= 4
  91.  
  92. #define GET16BITS(w,p,l)        w=(((WORD)(*p)<<8)+(WORD)*(p+1));       \
  93.                                 if(l<2)                                 \
  94.                                 {       truncated();                    \
  95.                                         return(FALSE);                  \
  96.                                 }                                       \
  97.                                 p += 2; l -= 2
  98.  
  99. #define GET8BITS(b,p,l)         b = *(p)++;                             \
  100.                                 if(--l<0)                               \
  101.                                 {       truncated();                    \
  102.                                         return(FALSE);                  \
  103.                                 }
  104.  
  105. #define GETVARLEN(dw,p,l)       for(dw=(LONG)(*p)&0x7f;(*(p)++)&0x80;)  \
  106.                                 {       if(--l<0)                       \
  107.                                         {       truncated();            \
  108.                                                 return(FALSE);          \
  109.                                         }                              \
  110.                                         dw <<=7;                        \
  111.                                         dw |= (LONG)(*p)&0x7f;          \
  112.                                 }                                      \
  113.                                 if(--l<0)                               \
  114.                                 {       truncated();                    \
  115.                                         return(FALSE);                  \
  116.                                 }
  117.  
  118. #define CHECKLEFT(l,v)          if(l<v)                                 \
  119.                                 {       truncated();                    \
  120.                                         return(FALSE);                  \
  121.                                 }
  122.  
  123.  
  124. #define MIDI_TXBYTE     0x404c9
  125.  
  126.  
  127. #define SEND(b)                 {                                       \
  128.                                         _kernel_swi_regs r;             \
  129.                                         r.r[0]=b;                       \
  130.                                         while(_kernel_swi(MIDI_TXBYTE,&r,&r) != 0) { \
  131.                                                 r.r[0]=b;                       \
  132.                                         }                               \
  133.                                 }                                       \
  134.  
  135.  
  136.  
  137.  
  138.  
  139. /* FUNCTION DEFS */
  140. BOOL            interp(BYTE *buffer, char *file, LONG len)
  141. {   BYTE        *pos=buffer,*next;
  142.     BYTE        running_status[MAX_TRACKS],last_running_status;
  143.     WORD        w;
  144.     LONG        dw,delta;
  145.     LONG        left=len;
  146.  
  147.     gFile=file;
  148.  
  149.     /* check header */
  150.     if((left<4)||(strncmp("MThd",(char*)pos,4)!=0))
  151.     {   (void)fprintf(stderr,"%s: %s is not a midi file\n",app_name,file);
  152.         return(FALSE);
  153.     }
  154.     pos += 4; left -= 4;
  155.  
  156.     /* find address of next chunk */
  157.     GET32BITS(dw,pos,left);
  158.     next=pos+dw;
  159. #ifdef DEBUG
  160.     (void)printf("pos is %lx len is %ld next would be %lx\n",pos-buffer,dw,
  161.         next-buffer);
  162. #endif
  163.  
  164.     /* get file format */
  165.     GET16BITS(format,pos,left);
  166.     switch (format)
  167.     {   /* OK we accept formats 0 and 1 */
  168.         case 0:
  169.         case 1:
  170.             break;
  171.         /* but we don't do any others */
  172.     default:
  173.         (void)fprintf(stderr,"%s: can't play %s, midi file type %d\n",app_name,
  174.             file,format);
  175.         return(FALSE);
  176.     }
  177.  
  178.     /* get number of tracks */
  179.     GET16BITS(tracks,pos,left);
  180.  
  181.     /* check tracks in range */
  182.     if(tracks > MAX_TRACKS)
  183.     {   (void)fprintf(stderr,"%s: %s has too many tracks :%d (%d allowed).\n",
  184.             app_name,file,tracks,MAX_TRACKS);
  185.         return(FALSE);
  186.     }
  187.  
  188.     /* get division - this is the division of a quarter note or if negative is
  189.        frame based. */
  190.     GET16BITS(w,pos,left);
  191.     division=(LONG)w;
  192.  
  193.     /* I don't suport the frame stuff yet! */
  194.     if(division < 0)
  195.     {   (void)fprintf(stderr,
  196.             "%s: file %s - don't support framed based files yet!", app_name,
  197.             file);
  198.         return(FALSE);
  199.     }
  200. #ifdef DEBUG
  201.     (void)printf("division = %f\n",division);
  202. #endif
  203.  
  204.     time_per_beat = (LONG)(CLK_TCK/2); /* default 120bpm = 2bps */
  205. #ifdef DEBUG
  206.     (void)printf("time per beat (1/%d sec) %ld\n", CLK_TCK, time_per_beat);
  207. #endif
  208.  
  209.     /* do some initialisation, track finding etc */
  210.     finished_tracks = 0;
  211.     for(trnr=0;trnr<tracks;trnr++)
  212.     {   CHECKLEFT(left,(next-pos));
  213.         left -= next-pos; pos = next;
  214.  
  215.         /* track start  */
  216.         if((left<4)||(strncmp("MTrk",(char*)pos,4)!=0))
  217.         {   (void)fprintf(stderr,"%s: %s parse error, track expected\n",
  218.                 app_name,file);
  219. #ifdef DEBUG
  220.             (void)printf("posn %lx, bytes around (-3..3) %02x %02x %02x %02x \
  221. %02x %02x %02x\n",pos-buffer,*(pos-3),*(pos-2),*(pos-1),*pos,*(pos+1),*(pos+2),
  222.                 *(pos+3));
  223. #endif
  224.             return(FALSE);
  225.         }
  226.         pos += 4; left -= 4;
  227.  
  228.         /* find address of next chunk */
  229.         GET32BITS(dw,pos,left);
  230.         track_pos[trnr] = pos;
  231.         next = pos+dw;
  232.         track_left[trnr] = dw;
  233. #ifdef DEBUG
  234.         (void)printf("pos is %lx len is %ld next would be %lx\n",pos-buffer,dw,
  235.             next-buffer);
  236. #endif
  237.  
  238.         /* get initial delta time */
  239.         GETVARLEN(dw,track_pos[trnr],track_left[trnr]);
  240.         track_delta[trnr]=dw * time_per_beat;
  241.         track_finished[trnr]=FALSE;
  242.         running_status[trnr] = 0xfe;
  243.         last_running_status = 0xfe;
  244.     }
  245.  
  246.     /* let the user know what's happening */
  247.     (void)printf("playing '%s' with %d %s\n",file,tracks,
  248.                                                 tracks==1?"track":"tracks");
  249.  
  250.     /* get start time */
  251.     clock_orig=clock();
  252.     clock_time=0;
  253.     if (f_Timing) SEND (0xFA);
  254.         
  255.     /* dispatcher */
  256.     while (finished_tracks != tracks)
  257.     {   BYTE    event;
  258.         clock_delta = (clock()-clock_orig)*division;
  259.         if (f_Timing && clock_delta >= clock_time) {
  260.             SEND(0xF8);
  261.             clock_time += (time_per_beat * division / 24);
  262.         }
  263.         for(trnr=0;trnr<tracks;trnr++)
  264.         {   if (!track_finished[trnr] & (clock_delta >= track_delta[trnr]))
  265.             {   GET8BITS(event,track_pos[trnr],track_left[trnr]);
  266.  
  267.                 /* parse event */
  268.                 switch (event)
  269.                 {   /* meta-events */
  270.                     case 0xff:
  271.                     {   if(!meta_event())
  272.                             return(FALSE);
  273.                         break;
  274.                     }
  275.                     /* sysex events */
  276.                     case 0xf0:
  277.                     case 0xf7:
  278.                     {   if(!sysex_event(event))
  279.                             return(FALSE);
  280.                         break;
  281.                     }
  282.                     case 0xf1:
  283.                     case 0xf2:
  284.                     case 0xf3:
  285.                     case 0xf4:
  286.                     case 0xf5:
  287.                     case 0xf6:
  288.                     {   if(!system_common(event))
  289.                             return(FALSE);
  290.                         break;
  291.                     }
  292.                     case 0xf8:
  293.                     case 0xf9:
  294.                     case 0xfa:
  295.                     case 0xfb:
  296.                     case 0xfc:
  297.                     case 0xfd:
  298.                     case 0xfe:
  299.                     {   if(!system_real_time())
  300.                             return(FALSE);
  301.                         break;
  302.                     }
  303.                     /* midi events */
  304.                     default:
  305.                     {   switch(event & 0xf0)
  306.                         {   /* 3 byte events */
  307.                             case 0x90:
  308.                             case 0x80:
  309.                             case 0xa0:
  310.                             case 0xb0:
  311.                             case 0xe0:
  312.                             {   BYTE    c;
  313.                                 SEND(event);
  314.                                 GET8BITS(c,track_pos[trnr],track_left[trnr]);
  315.                                 SEND(c);
  316.                                 GET8BITS(c,track_pos[trnr],track_left[trnr]);
  317.                                 SEND(c);
  318.                                 running_status[trnr] = event;
  319.                                 last_running_status = event;
  320.                                 break;
  321.                             }
  322.                             /* program change */
  323.                             case 0xc0:
  324.                             {   BYTE    c;
  325.                                 GET8BITS(c,track_pos[trnr],track_left[trnr]);
  326.                                 if (f_Program)
  327.                                 {   SEND(event);
  328.                                     SEND(c);
  329.                                     running_status[trnr] = event;
  330.                                     last_running_status = event;
  331.                                 }
  332.                                 break;
  333.                             }
  334.                             /* channel pressure */
  335.                             case 0xd0:
  336.                             {   BYTE    c;
  337.                                 GET8BITS(c,track_pos[trnr],track_left[trnr]);
  338.                                 if (f_Channel_pressure)
  339.                                 {   SEND(event);
  340.                                     SEND(c);
  341.                                     running_status[trnr] = event;
  342.                                     last_running_status = event;
  343.                                 }
  344.                                 break;
  345.                             }
  346.                             default:
  347.                             {   /* running status */
  348.                                 if(running_status[trnr]!=last_running_status)
  349.                                 {   SEND(running_status[trnr]);
  350.                                     last_running_status=running_status[trnr];
  351.                                 }
  352.                                 if((event&0x80)==0)
  353.                                 {   SEND(event);
  354. #ifdef DEBUG
  355.                                     (void)printf("running stat (%02x)  %02x\n",
  356.                                         running_status[trnr],event);
  357. #endif
  358.                                     switch(running_status[trnr] & 0xf0)
  359.                                     {   /* 3 byte events */
  360.                                         case 0x90:
  361.                                         case 0x80:
  362.                                         case 0xa0:
  363.                                         case 0xb0:
  364.                                         case 0xe0:
  365.                                         {   BYTE c;
  366.                                             GET8BITS(c,track_pos[trnr],
  367.                                                 track_left[trnr]);
  368.                                             SEND(c);
  369.                                             break;
  370.                                         }
  371.                                         /* ignoring other 0xf? events - naughty
  372.                                             aren't I */
  373.                                     }
  374.                                 }
  375.                             }
  376.                         }
  377.                     }
  378.                 }
  379.  
  380.                 /* get delta time  - but only if we're still going on this
  381.                    track */
  382.                 if(!track_finished[trnr])
  383.                 {   GETVARLEN(delta,track_pos[trnr],track_left[trnr]);
  384.                     track_delta[trnr] += delta * time_per_beat;
  385.                 }
  386.             }
  387.         }
  388.         /* CHECK TO SEE IF CTRL C/S PRESSED */
  389.         if(bbc_inkey(-2))   /* control pressed */
  390.         {   
  391.             if (bbc_inkey(-83)) { /* CTRL C */
  392.                     printf("\n** Exit by CTRL C **\n");
  393.                     all_notes_off();
  394.                     return(TRUE);
  395.             }
  396.                 
  397.             if (bbc_inkey(-82)) {  /* CTRL S */
  398.                     printf("\n** Skip track by CTRL S **\n");
  399.                     all_notes_off();
  400.                     return(FALSE);
  401.                 
  402.             }
  403.         }
  404.     }
  405.     if (f_Timing) SEND (0xFC);
  406.  
  407.     return(FALSE);
  408. }
  409.  
  410.  
  411. /* system exclusive events */
  412. int     sysex_event(BYTE event)
  413. {   LONG        length,l;
  414.     GETVARLEN(length,track_pos[trnr],track_left[trnr]);
  415.     if(f_Sysex)
  416.     {   BYTE    c;
  417.         if(event==0xf0)
  418.                 SEND(0xf0);
  419.         for(l=0;l<length;l++)
  420.         {  GET8BITS(c,track_pos[trnr],track_left[trnr]);
  421.            SEND(c);
  422.         }
  423.     }
  424.     else
  425.     {   CHECKLEFT(track_left[trnr],length);
  426.         track_pos[trnr] += length;
  427.         track_left[trnr] -= length;
  428.     }
  429.     return(TRUE);
  430. }
  431.  
  432. /* meta-events */
  433. int meta_event(void)
  434. {   BYTE        type;
  435.     LONG        length;
  436.  
  437.     /* get type of meta event */
  438.     GET8BITS(type,track_pos[trnr],track_left[trnr]);
  439. #ifdef DEBUG
  440.     (void)printf("meta-event %02x ",type);
  441. #endif
  442.  
  443.     /* get length */
  444.     GETVARLEN(length,track_pos[trnr],track_left[trnr]);
  445. #ifdef DEBUG
  446.     (void)printf("length %ld\n",length);
  447. #endif
  448.  
  449.     switch(type)
  450.     {   /* textual meta-events */
  451.         case 0x01:
  452.         case 0x02:
  453.         case 0x03:
  454.         case 0x04:
  455.         case 0x05:
  456.         case 0x06:
  457.         case 0x07:
  458.         {   int         flag;
  459.             char        *msg;
  460.             switch(type)
  461.             {   case 0x01:
  462.                     flag=f_text;
  463.                     msg="Text: \"";
  464.                     break;
  465.                 case 0x02:
  466.                     flag=f_copyright;
  467.                     msg="Copyright: \"";
  468.                     break;
  469.                 case 0x03:
  470.                     flag=f_track_name;
  471.                     msg="Track\\Sequence: \"";
  472.                     break;
  473.                 case 0x04:
  474.                     flag=f_instrument;
  475.                     msg="Instrument: \"";
  476.                     break;
  477.                 case 0x05:
  478.                     flag=f_lyric;
  479.                     break;
  480.                 case 0x06:
  481.                     flag=f_marker;
  482.                     msg="Marker: \"";
  483.                     break;
  484.                 case 0x07:
  485.                     flag=f_prompt;
  486.                     msg="Prompt: \"";
  487.                     break;
  488.             }
  489.             if (flag)
  490.             {   LONG    l;
  491.                 BYTE    c;
  492.                 /* lyrics should have no header */
  493.                 if(type!=0x05)
  494.                     printf(msg);
  495.                 for(l=0;l<length;l++)
  496.                 {   GET8BITS(c,track_pos[trnr],track_left[trnr]);
  497.                     putchar(c);
  498.                 }
  499.                 /* lyrics should be on same line */
  500.                 if(type!=0x05)
  501.                     printf("\"[Tr %d]\n",trnr);
  502.             }
  503.             else
  504.             {   CHECKLEFT(track_left[trnr],length);
  505.                 track_pos[trnr] += length;
  506.                 track_left[trnr] -= length;
  507.             }
  508.             break;
  509.         }
  510.         /* u-sec tempo set */
  511.         case 0x51:
  512.         {   LONG        t;
  513.             BYTE        c;
  514.             int         i;
  515.             long        delta;
  516.             GET8BITS(c,track_pos[trnr],track_left[trnr]);
  517.             t=(LONG)c<<16;
  518.             GET8BITS(c,track_pos[trnr],track_left[trnr]);
  519.             t += (LONG)c<<8;
  520.             GET8BITS(c,track_pos[trnr],track_left[trnr]);
  521.             t += (LONG)c;
  522. #ifdef DEBUG
  523.             (void)printf("usec %ld ",t);
  524. #endif
  525.             t=(t*(LONG)CLK_TCK)/1000000L;
  526.  
  527.             /* adjust all time values to the new unit system */
  528.             /* Note: the calculations must be in long, not LONG as some of
  529.                the intermediate values may become negative */
  530.  
  531. /* printf("tpb= %ld t= %ld delta=%ld clock_time=%ld\n",
  532.         time_per_beat, t, delta, clock_time);
  533. */      
  534.             delta = track_delta[trnr];
  535.             clock_time = (clock_time-delta)*(long)t/time_per_beat + delta;
  536.             for (i=0;i<tracks;i++) {
  537. /* printf("trnr= %d delta= %ld ", i, track_delta[i]);       */
  538.                 if (!track_finished[i])
  539.                     track_delta[i] =
  540.                         (track_delta[i]-delta)*(long)t/time_per_beat + delta;
  541. /* printf("=> %ld\n", track_delta[i]);      */
  542.             }
  543.             time_per_beat = t;
  544. #ifdef DEBUG
  545.             (void)printf("our %ld\n",time_per_beat);
  546. #endif
  547.             break;
  548.         }
  549.  
  550.         /* end of track - can't be bothered to check left == 0 too */
  551.         case 0x2f:
  552.             track_finished[trnr]=TRUE;
  553. /* printf("track %d finished\n", trnr); */
  554.             finished_tracks++;
  555.             break;
  556.  
  557.             /* ignore rest */
  558.         default:
  559.             CHECKLEFT(track_left[trnr],length);
  560.             track_pos[trnr] += length;
  561.             track_left[trnr] -= length;
  562.             break;
  563.     }
  564.     return(TRUE);
  565. }
  566.  
  567. static int      system_common(BYTE event)
  568. {   switch(event)
  569.     {   /* 3 byte instructions */
  570.         case 0xf2:
  571.         {   CHECKLEFT(track_left[trnr],2);
  572.             track_pos[trnr] += 2;
  573.             track_left[trnr] -= 2;
  574.             break;
  575.         }
  576.         /* 2 byte instructions */
  577.         case 0xf1:
  578.         case 0xf3:
  579.         {   CHECKLEFT(track_left[trnr],1);
  580.             track_pos[trnr] += 1;
  581.             track_left[trnr] -= 1;
  582.             break;
  583.         }
  584.         /* rest are single byte */
  585.     }
  586.     return(TRUE);
  587. }
  588.  
  589. static int      system_real_time(void)
  590. {       /* all 1 byte so ignore */
  591.         return(TRUE);
  592. }
  593.  
  594. static void   all_notes_off(void)
  595. {
  596.     int i,j;
  597.  
  598.     /* MANUALLY TURN ALL NOTES OFF */
  599.  
  600.     printf("Turning all notes off...\n");
  601.  
  602.     if (f_Timing) SEND (0xFC);
  603.  
  604.     for(i=0;i<16;i++) {
  605.         SEND((BYTE)(0x90+i));
  606.         for(j=0;j<128;j++) {
  607.             SEND(j);
  608.             SEND(0);
  609.         }
  610.     }
  611. }
  612.  
  613. /* general error messages - I got fed up typing these over and over again */
  614. static void     truncated(void)
  615. {   (void)fprintf(stderr,"%s: %s truncated\n",app_name,gFile);
  616. }
  617.  
  618. /*
  619.  * REVISION LOG
  620.  * ============
  621.  * 0.1  SGoldthorpe     20-Mar-91       Created for Atari ST / Sozobon C.  It's
  622.  *                                      a bit atari specific in places but i've
  623.  *                                      tried to make it UNIX(tm) looking for
  624.  *                                      easier porting (if anyone feels brave
  625.  *                                      enough to try.
  626.  * 0.2  SGoldthorpe      7-Apr-91       Messed up the code in mp_intp to
  627.  *                                      allow type 1 midi files.  Timing is
  628.  *                                      still a bit hairy but it plays 80%
  629.  *                                      of the files I have OK.
  630.  * 0.3  SGoldthorpe     27-May-91       Reformatted & tidied up, sorted out
  631.  *                                      running status and added flags.
  632.  * 0.4  SGoldthorpe     20-Jul-91       Generally restructed and tidied up and
  633.  *                                      added sysex events.
  634.  *
  635.  */
  636.